﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.IO;
using System.Text;
using System.Windows.Forms;

using SBPweb.Modules.Modularity;
using SBPweb.Modules.Smartparts;

using SBPweb.MediaCenter.Tools.WF;

using SBPweb.MediaCenter.Modules.Viewer.ModifyDescriptors;

namespace SBPweb.MediaCenter.Modules.Viewer.WF
{
	public partial class ViewerControl : UserControl, ISmartpart
	{
		#region Private constants

		private const int mThumbnailMaxSizeX = 32;
		private const int mThumbnailMaxSizeY = 32;
		private StartupZoomStyle mStartUpZoomStyle = StartupZoomStyle.Reduce_Or_Enlarge;

		#endregion

		#region Private members

		private bool pIsModal;
		private Aligning pAlign;
		private IModule pParentModule;

		private Image originalPhoto;
		private int mPercent = 100;

		#endregion

		public ViewerControl(IModule parentModule)
        {
			pParentModule = parentModule;
			InitializeComponent();
			Align = Aligning.Fill;
        }

		#region ISmartpart Members

		public Aligning Align
		{
			get
			{
				return pAlign;
			}
			set
			{
				pAlign = value;
				Dock = AligningConverter.AligningToDockStyle(value);
			}
		}

		public IModule ParentModule
		{
			get
			{
				return pParentModule;
			}
		}

		public bool IsVisible
		{
			get
			{
				return base.Visible;
			}
			set
			{
				base.Visible = value;
			}
		}

		public bool IsEnabled
		{
			get
			{
				return base.Enabled;
			}
			set
			{
				base.Enabled = value;
			}
		}

		public bool IsModal
		{
			get
			{
				return pIsModal;
			}
		}

		#endregion

		#region Public properties

		public Image Image
		{
			get
			{
				return pictureBox.Image;
			}
			set
			{
				pnlPictureBox.HorizontalScroll.Visible = false;
				pnlPictureBox.VerticalScroll.Visible = false;
				pictureBox.Image = value;
				originalPhoto = value;
				SetPercentAfterLoadImage();
				if (Percent != 100)
				{
					ZoomToCurrentPercent();
					//pictureBox.Refresh();
				}
				if (OnImageChanged != null)
				{
					OnImageChanged();
				}
				if (value != null)
				{
					this.Size = pictureBox.Image.Size;
				}
				else
				{
					this.Size = new Size();
				}
			}
		}

		public Image VisiblePartOfImage
		{
			get
			{
				int targetWidth = (int)(originalPhoto.Width * Percent / 100.0);
				int targetHeight = (int)(originalPhoto.Height * Percent / 100.0);

				Bitmap bmZoomedPhoto = new Bitmap(targetWidth, targetHeight, PixelFormat.Format24bppRgb);
				bmZoomedPhoto.SetResolution(originalPhoto.HorizontalResolution, originalPhoto.VerticalResolution);
				Graphics grZoomedPhoto = Graphics.FromImage(bmZoomedPhoto);
				grZoomedPhoto.SmoothingMode = SmoothingMode.AntiAlias;
				grZoomedPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;
				grZoomedPhoto.PixelOffsetMode = PixelOffsetMode.HighQuality;
				grZoomedPhoto.DrawImage(originalPhoto, new Rectangle(0, 0, targetWidth, targetHeight), 0, 0, originalPhoto.Width, originalPhoto.Height, GraphicsUnit.Pixel);
				MemoryStream mmZ = new MemoryStream();
				bmZoomedPhoto.Save(mmZ, System.Drawing.Imaging.ImageFormat.Jpeg);
				bmZoomedPhoto.Dispose();
				grZoomedPhoto.Dispose();

				Image zoomedImage = Image.FromStream(mmZ);

				int newWidth = pnlPictureBox.ClientRectangle.Width;
				if (newWidth > zoomedImage.Width)
				{
					newWidth = zoomedImage.Width;
				}
				int newHeight = pnlPictureBox.ClientRectangle.Height;
				if (newHeight > zoomedImage.Height)
				{
					newHeight = zoomedImage.Height;
				}
				Bitmap bmCroppedPhoto = new Bitmap(newWidth, newHeight, PixelFormat.Format24bppRgb);
				bmCroppedPhoto.SetResolution(zoomedImage.HorizontalResolution, zoomedImage.VerticalResolution);
				Graphics grCroppedPhoto = Graphics.FromImage(bmCroppedPhoto);
				grCroppedPhoto.SmoothingMode = SmoothingMode.AntiAlias;
				grCroppedPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;
				grCroppedPhoto.PixelOffsetMode = PixelOffsetMode.HighQuality;
				grCroppedPhoto.DrawImage(zoomedImage, new Rectangle(0, 0, newWidth, newHeight), pnlPictureBox.HorizontalScroll.Value, pnlPictureBox.VerticalScroll.Value, newWidth, newHeight, GraphicsUnit.Pixel);
				MemoryStream mmC = new MemoryStream();
				bmCroppedPhoto.Save(mmC, System.Drawing.Imaging.ImageFormat.Jpeg);
				bmCroppedPhoto.Dispose();
				grCroppedPhoto.Dispose();

				return Image.FromStream(mmC);
			}
		}

		public Image Thumbnail
		{
			get
			{
				if (pictureBox.Image == null)
				{
					return null;
				}
				else
				{
					Bitmap OrigImg = (Bitmap)pictureBox.Image.Clone();
					float xDivision = OrigImg.Width / mThumbnailMaxSizeX;
					float yDivision = OrigImg.Height / mThumbnailMaxSizeY;
					int sizeX = mThumbnailMaxSizeX;
					int sizeY = mThumbnailMaxSizeY;
					if (xDivision > yDivision)
					{
						sizeY = (int)(OrigImg.Height / xDivision);
					}
					else
					{
						sizeX = (int)(OrigImg.Width / yDivision);
					}
					Bitmap NewImg = new Bitmap(OrigImg, new Size(sizeX, sizeY));
					return NewImg as Image;
				}
			}
		}

		public PictureBoxSizeMode SizeMode
		{
			get
			{
				return pictureBox.SizeMode;
			}
			set
			{
				pictureBox.SizeMode = value;
			}
		}

		public int Percent
		{
			get
			{
				return mPercent;
			}
			set
			{
				int mOriginalPercent = mPercent;
				mPercent = value;
				if (OnZoomPercentChanged != null)
				{
					OnZoomPercentChanged(mOriginalPercent, mPercent);
				}
				tsslZoom.Text = string.Format("{0} %", Percent);
			}
		}

		public StartupZoomStyle StartupZoomStyle
		{
			get
			{
				return mStartUpZoomStyle;
			}
			set
			{
				mStartUpZoomStyle = value;
			}
		}

		#endregion

		#region Overridden method

		public override void Refresh()
		{
			pictureBox.Refresh();
			base.Refresh();
		}

		#endregion

		#region Delegate & event

		public delegate void ImageChangedHandler();
		public event ImageChangedHandler OnImageChanged;

		public delegate void ZoomPercentChangedHandler(int originalpercent, int newPercent);
		public event ZoomPercentChangedHandler OnZoomPercentChanged;

		public delegate void ImageMoveFinishedHandler();
		public event ImageMoveFinishedHandler OnImageMoved;

		public delegate void ImageZoomFinishedHandler();
		public event ImageZoomFinishedHandler OnImageZoomed;

		public delegate void ImageFlipFinishedHandler();
		public event ImageFlipFinishedHandler OnImageFlipped;

		public delegate void ImageRotateFinishedHandler();
		public event ImageRotateFinishedHandler OnImageRotated;

		public delegate void ImageModifiedHandler();
		public event ImageModifiedHandler OnImageModified;

		#endregion

		#region Public methods

		public void MoveImage(MoveDirections direction)
		{
			switch (direction)
			{
				case MoveDirections.Start:
					MoveStart();
					break;
				case MoveDirections.Left:
					MoveLeft();
					break;
				case MoveDirections.Right:
					MoveRight();
					break;
				case MoveDirections.Up:
					MoveUp();
					break;
				case MoveDirections.Down:
					MoveDown();
					break;
			}
		}

		public void Flip(FlipAxis flip)
		{
			switch (flip)
			{
				case FlipAxis.None:
					break;
				case FlipAxis.X:
					FlipX();
					break;
				case FlipAxis.Y:
					FlipY();
					break;
				case FlipAxis.XY:
					FlipXY();
					break;
			}
		}

		public void Rotate(RotateDeg deg)
		{
			switch (deg)
			{
				case RotateDeg.Deg0:
					break;
				case RotateDeg.Deg90:
					RotateRight();
					break;
				case RotateDeg.Deg180:
					RotateHalf();
					break;
				case RotateDeg.Deg270:
					RotateLeft();
					break;
			}
		}

		public void Zoom(ZoomStyles zoom)
		{
			switch (zoom)
			{
				case ZoomStyles.Original:
					ZoomOriginal();
					break;
				case ZoomStyles.ZoomIn:
					ZoomIn();
					break;
				case ZoomStyles.ZoomOut:
					ZoomOut();
					break;
			}
		}

		#endregion

		#region Private helper methods

		private void FlipX()
		{
			if (originalPhoto == null)
			{
				return;
			}

			pictureBox.Image.RotateFlip(RotateFlipType.RotateNoneFlipX);
			pictureBox.Refresh();
			if (OnImageFlipped != null)
			{
				OnImageFlipped();
			}
			if (OnImageModified != null)
			{
				OnImageModified();
			}
		}

		private void FlipY()
		{
			if (originalPhoto == null)
			{
				return;
			}

			pictureBox.Image.RotateFlip(RotateFlipType.RotateNoneFlipY);
			pictureBox.Refresh();
			if (OnImageFlipped != null)
			{
				OnImageFlipped();
			}
			if (OnImageModified != null)
			{
				OnImageModified();
			}
		}

		private void FlipXY()
		{
			if (originalPhoto == null)
			{
				return;
			}

			pictureBox.Image.RotateFlip(RotateFlipType.RotateNoneFlipXY);
			pictureBox.Refresh();
			if (OnImageFlipped != null)
			{
				OnImageFlipped();
			}
			if (OnImageModified != null)
			{
				OnImageModified();
			}
		}

		private void RotateRight()
		{
			if (originalPhoto == null)
			{
				return;
			}

			pictureBox.Image.RotateFlip(RotateFlipType.Rotate90FlipNone);
			pictureBox.Refresh();
			if (OnImageRotated != null)
			{
				OnImageRotated();
			}
			if (OnImageModified != null)
			{
				OnImageModified();
			}
		}

		private void RotateLeft()
		{
			if (originalPhoto == null)
			{
				return;
			}

			pictureBox.Image.RotateFlip(RotateFlipType.Rotate270FlipNone);
			pictureBox.Refresh();
			if (OnImageRotated != null)
			{
				OnImageRotated();
			}
			if (OnImageModified != null)
			{
				OnImageModified();
			}
		}

		private void RotateHalf()
		{
			if (originalPhoto == null)
			{
				return;
			}

			pictureBox.Image.RotateFlip(RotateFlipType.Rotate180FlipNone);
			pictureBox.Refresh();
			if (OnImageRotated != null)
			{
				OnImageRotated();
			}
			if (OnImageModified != null)
			{
				OnImageModified();
			}
		}

		private void MoveStart()
		{
			if (originalPhoto == null)
			{
				return;
			}

			if (!pnlPictureBox.VerticalScroll.Visible)
			{
				return;
			}
			pnlPictureBox.VerticalScroll.Value = 0;
			pnlPictureBox.HorizontalScroll.Value = 0;
			if (OnImageMoved != null)
			{
				OnImageMoved();
			}
			if (OnImageModified != null)
			{
				OnImageModified();
			}
		}

		private void MoveUp()
		{
			MoveUp(pnlPictureBox.VerticalScroll.SmallChange);
		}

		private void MoveUp(int value)
		{
			if (originalPhoto == null)
			{
				return;
			}

			if (!pnlPictureBox.VerticalScroll.Visible)
			{
				return;
			}
			if (pnlPictureBox.VerticalScroll.Value <= pnlPictureBox.VerticalScroll.Minimum)
			{
				return;
			}
			if (value <= 0)
			{
				return;
			}
			int newValue = pnlPictureBox.VerticalScroll.Value - value;
			if (newValue < pnlPictureBox.VerticalScroll.Minimum)
			{
				newValue = pnlPictureBox.VerticalScroll.Minimum;
			}
			pnlPictureBox.VerticalScroll.Value = newValue;
			if (OnImageMoved != null)
			{
				OnImageMoved();
			}
			if (OnImageModified != null)
			{
				OnImageModified();
			}
		}

		private void MoveDown()
		{
			MoveDown(pnlPictureBox.VerticalScroll.SmallChange);
		}

		private void MoveDown(int value)
		{
			if (originalPhoto == null)
			{
				return;
			}

			if (!pnlPictureBox.VerticalScroll.Visible)
			{
				return;
			}
			if (pnlPictureBox.VerticalScroll.Value >= pnlPictureBox.VerticalScroll.Maximum)
			{
				return;
			}
			if (value <= 0)
			{
				return;
			}
			int newValue = pnlPictureBox.VerticalScroll.Value + value;
			if (newValue > pnlPictureBox.VerticalScroll.Maximum)
			{
				newValue = pnlPictureBox.VerticalScroll.Maximum;
			}
			pnlPictureBox.VerticalScroll.Value = newValue;
			if (OnImageMoved != null)
			{
				OnImageMoved();
			}
			if (OnImageModified != null)
			{
				OnImageModified();
			}
		}

		private void MoveLeft()
		{
			MoveLeft(pnlPictureBox.HorizontalScroll.SmallChange);
		}

		private void MoveLeft(int value)
		{
			if (originalPhoto == null)
			{
				return;
			}

			if (!pnlPictureBox.HorizontalScroll.Visible)
			{
				return;
			}
			if (pnlPictureBox.HorizontalScroll.Value <= pnlPictureBox.HorizontalScroll.Minimum)
			{
				return;
			}
			if (value <= 0)
			{
				return;
			}
			int newValue = pnlPictureBox.HorizontalScroll.Value - value;
			if (newValue < pnlPictureBox.HorizontalScroll.Minimum)
			{
				newValue = pnlPictureBox.HorizontalScroll.Minimum;
			}
			pnlPictureBox.HorizontalScroll.Value = newValue;
			if (OnImageMoved != null)
			{
				OnImageMoved();
			}
			if (OnImageModified != null)
			{
				OnImageModified();
			}
		}

		private void MoveRight()
		{
			MoveRight(pnlPictureBox.HorizontalScroll.SmallChange);
		}

		private void MoveRight(int value)
		{
			if (originalPhoto == null)
			{
				return;
			}

			if (!pnlPictureBox.HorizontalScroll.Visible)
			{
				return;
			}
			if (pnlPictureBox.HorizontalScroll.Value >= pnlPictureBox.HorizontalScroll.Maximum)
			{
				return;
			}
			if (value <= 0)
			{
				return;
			}
			int newValue = pnlPictureBox.HorizontalScroll.Value + value;
			if (newValue > pnlPictureBox.HorizontalScroll.Maximum)
			{
				newValue = pnlPictureBox.HorizontalScroll.Maximum;
			}
			pnlPictureBox.HorizontalScroll.Value = newValue;
			if (OnImageMoved != null)
			{
				OnImageMoved();
			}
			if (OnImageModified != null)
			{
				OnImageModified();
			}
		}

		private void ZoomIn()
		{
			if (originalPhoto == null)
			{
				return;
			}

			int oldPercent = Percent;
			Percent = (int)(Percent * 1.1 / 5) * 5;
			if (oldPercent == Percent)
			{
				Percent += 5;
			}

			if (Percent > 1000)
			{
				Percent = 1000;
			}

			ZoomToCurrentPercent();
		}

		private void ZoomOut()
		{
			if (originalPhoto == null)
			{
				return;
			}

			int oldPercent = Percent;

			Percent = (int)(Percent * 0.9 / 5) * 5;

			if (oldPercent == Percent)
			{
				Percent -= 5;
			}

			if (Percent < 10)
			{
				Percent = 10;
			}

			ZoomToCurrentPercent();
		}

		private void ZoomToCurrentPercent()
		{
			if (originalPhoto == null)
			{
				return;
			}

			int targetWidth = (int)(originalPhoto.Width * Percent / 100.0);
			int targetHeight = (int)(originalPhoto.Height * Percent / 100.0);

			Bitmap bmPhoto = new Bitmap(targetWidth, targetHeight, PixelFormat.Format24bppRgb);
			bmPhoto.SetResolution(originalPhoto.HorizontalResolution, originalPhoto.VerticalResolution);
			Graphics grPhoto = Graphics.FromImage(bmPhoto);
			grPhoto.SmoothingMode = SmoothingMode.AntiAlias;
			grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;
			grPhoto.PixelOffsetMode = PixelOffsetMode.HighQuality;
			grPhoto.DrawImage(originalPhoto, new Rectangle(0, 0, targetWidth, targetHeight), 0, 0, originalPhoto.Width, originalPhoto.Height, GraphicsUnit.Pixel);
			MemoryStream mm = new MemoryStream();
			bmPhoto.Save(mm, System.Drawing.Imaging.ImageFormat.Jpeg);
			bmPhoto.Dispose();
			grPhoto.Dispose();
			pictureBox.Image = Image.FromStream(mm);

			if (OnImageZoomed != null)
			{
				OnImageZoomed();
			}
			if (OnImageModified != null)
			{
				OnImageModified();
			}
		}

		private void ZoomOriginal()
		{
			if (originalPhoto == null)
			{
				return;
			}

			Percent = 100;

			pictureBox.Image = originalPhoto;
			if (OnImageZoomed != null)
			{
				OnImageZoomed();
			}
			if (OnImageModified != null)
			{
				OnImageModified();
			}
		}

		private void SetPercentAfterLoadImage()
		{
			if (pictureBox.Image == null)
			{
				Percent = 100;
				return;
			}

			Percent = 100;
			pnlPictureBox.VerticalScroll.Visible = false;
			pnlPictureBox.HorizontalScroll.Visible = false;
			float xDivision = (float)pictureBox.Image.Width / pnlPictureBox.Width;
			float yDivision = (float)pictureBox.Image.Height / pnlPictureBox.Height;

			switch (mStartUpZoomStyle)
			{
				case StartupZoomStyle.None:
					Percent = 100;
					break;
				case StartupZoomStyle.Only_Reduce:
					if (xDivision > 1 || yDivision > 1)
					{
						Percent = (int)((100 / ((xDivision > yDivision ? xDivision : yDivision) * 100)) * 100);
					}
					break;
				case StartupZoomStyle.Only_Enlarge:
					if (xDivision < 1 && yDivision < 1)
					{
						Percent = (int)((100 / ((xDivision > yDivision ? xDivision : yDivision) * 100)) * 100);
					}
					break;
				case StartupZoomStyle.Reduce_Or_Enlarge:
					if (xDivision > 1 || yDivision > 1)
					{
						Percent = (int)((100 / ((xDivision > yDivision ? xDivision : yDivision) * 100)) * 100);
					}
					else if (xDivision < 1 && yDivision < 1)
					{
						Percent = (int)((100 / ((xDivision > yDivision ? xDivision : yDivision) * 100)) * 100);
					}
					break;
			}
		}

		#endregion

		//TODO: Remove the next region. Call this features from the module.
		#region REMOVABLE!!!

		private void tsbLeft_Click(object sender, EventArgs e)
		{
			MoveImage(MoveDirections.Left);
		}

		private void tsbRight_Click(object sender, EventArgs e)
		{
			MoveImage(MoveDirections.Right);
		}

		private void tsbUp_Click(object sender, EventArgs e)
		{
			MoveImage(MoveDirections.Up);
		}

		private void tsbDown_Click(object sender, EventArgs e)
		{
			MoveImage(MoveDirections.Down);
		}

		private void tsbRotateLeft_Click(object sender, EventArgs e)
		{
			Rotate(RotateDeg.Deg270);
		}

		private void tsbRotateHalf_Click(object sender, EventArgs e)
		{
			Rotate(RotateDeg.Deg180);
		}

		private void tsbRotateRight_Click(object sender, EventArgs e)
		{
			Rotate(RotateDeg.Deg90);
		}

		private void tsbFlipX_Click(object sender, EventArgs e)
		{
			Flip(FlipAxis.X);
		}

		private void tsbFlipY_Click(object sender, EventArgs e)
		{
			Flip(FlipAxis.Y);
		}

		private void tsbFlipXY_Click(object sender, EventArgs e)
		{
			Flip(FlipAxis.XY);
		}

		private void tsbZoomIn_Click(object sender, EventArgs e)
		{
			Zoom(ZoomStyles.ZoomIn);
		}

		private void tsbZoomOut_Click(object sender, EventArgs e)
		{
			Zoom(ZoomStyles.ZoomOut);
		}

		private void tsbStartupZoom_Click(object sender, EventArgs e)
		{
			tsbStartupZoomNone.Checked = tsbStartupZoomReduce.Checked = tsbStartupZoomEnlarge.Checked = tsbStartupZoomReduceOrEnlarge.Checked = false;
			ToolStripButton tsb = (sender as ToolStripButton);
			tsb.Checked = true;
			switch (tsb.Name)
			{
				case "tsbStartupZoomNone":
					mStartUpZoomStyle = StartupZoomStyle.None;
					break;
				case "tsbStartupZoomReduce":
					mStartUpZoomStyle = StartupZoomStyle.Only_Reduce;
					break;
				case "tsbStartupZoomEnlarge":
					mStartUpZoomStyle = StartupZoomStyle.Only_Enlarge;
					break;
				case "tsbStartupZoomReduceOrEnlarge":
					mStartUpZoomStyle = StartupZoomStyle.Reduce_Or_Enlarge;
					break;
			}
		}

		#endregion
	}
}
